package top.broncho.formatdemo

import android.graphics.*
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.hi.dhl.binding.viewbind
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks
import top.broncho.anko.AnkoLogger
import top.broncho.anko.info
import top.broncho.anko.toast
import top.broncho.anko.warn
import top.broncho.formatdemo.databinding.ActivityMainBinding
import top.broncho.libjpeg.JpegUtils
import top.broncho.yuv.YuvUtils
import java.io.*
import java.nio.ByteBuffer


class MainActivity : AppCompatActivity(R.layout.activity_main), AnkoLogger {
    private val binding by viewbind<ActivityMainBinding>()
    private var width = 3000
    private var height = 4000

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.btnRgb2yuv.clicks().onEach {
            rgb2Yuv()
        }.launchIn(lifecycleScope)
        binding.btnYuv2rgb.clicks().onEach {
            yuv2Rgb()
        }.launchIn(lifecycleScope)
        binding.btnScaleYuv.clicks().onEach {
            scaleYuv420sp()
        }.launchIn(lifecycleScope)
        binding.btnRotateYuv.clicks().onEach {
            rotateYuv420sp()
        }.launchIn(lifecycleScope)

    }

    fun rgb2Yuv() {
        try {
            val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            bitmap.isPremultiplied = true
            val canvas = Canvas(bitmap)
            //画白底
            canvas.drawColor(Color.WHITE)

            // 画logo
            val drawable = ContextCompat.getDrawable(
                applicationContext,
                R.drawable.ic_white_balance_sunlight_normal
            )!!
            val logoSize = width / 3
            val logoLeft = (width - logoSize) / 2
            val logoTop = (height - logoSize) / 2
            drawable.setBounds(logoLeft, logoTop, logoLeft + logoSize, logoTop + logoSize)
            drawable.draw(canvas)

            val file = File(getExternalFilesDir("YUV"), "NV21_${width}x${height}.yuv")
            val os: OutputStream = FileOutputStream(file)
            val buffer: ByteBuffer = ByteBuffer.allocate(bitmap.width * bitmap.height * 4)
            bitmap.copyPixelsToBuffer(buffer)
            val yuvData = ByteArray(bitmap.width * bitmap.height * 3 / 2)
            val start = System.currentTimeMillis()
            YuvUtils.ARGBToNv21(
                buffer.array(),
                yuvData,
                bitmap.width,
                bitmap.height
            )
            warn { "width*height:${bitmap.width}x${bitmap.height}, cost:${System.currentTimeMillis() - start}ms" }
            toast("转换完成" + bitmap.width + "x" + bitmap.height + ", 耗时:" + (System.currentTimeMillis() - start) + "ms")
            os.write(yuvData)
            os.flush()
            os.close()
            val result = JpegUtils.NV21ToJPEG(yuvData, bitmap.width, bitmap.height)
            info { "NV21ToJPEG: result=$result" }
            val bm = BitmapFactory.decodeByteArray(result, 0, result.size)
            binding.ivResult.setImageBitmap(bm)

            FileOutputStream(File(getExternalFilesDir("YUV"), "yuv2jpeg.jpeg")).use {
                it.write(result)
            }

            val yuvImage = YuvImage(yuvData, ImageFormat.NV21, width, height, null)
            yuvImage.compressToJpeg(
                Rect(0, 0, width, height),
                100,
                FileOutputStream(File(getExternalFilesDir("YUV"), "nv21.jpg"))
            )
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun yuv2Rgb() {
        val yuvData = ByteArray(width * height * 3 / 2)
        val rgbaData = ByteArray(width * height * 4)
        val file = File(getExternalFilesDir("YUV"), "NV21_${width}x${height}.yuv")
        try {
            val fis = FileInputStream(file)
            fis.read(yuvData, 0, width * height * 3 / 2)

            val start = System.currentTimeMillis()
            YuvUtils.NV21ToABGR(yuvData, rgbaData, width, height)
            val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            val buffer = ByteBuffer.allocate(width * height * 4)
            buffer.put(rgbaData)
            buffer.rewind()
            bitmap.copyPixelsFromBuffer(buffer)
            warn { "yuv2Rgb: cost=${System.currentTimeMillis() - start}ms" }

            FileOutputStream(File(getExternalFilesDir("YUV"), "argb.jpeg")).use {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)

            }
            binding.ivResult.setImageBitmap(bitmap)
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun scaleYuv420sp() {
        val src = ByteArray(width * height * 3 / 2)
        val dst = ByteArray(width * height * 3 / 2 / 5 / 5)
        val file = File(getExternalFilesDir("YUV"), "NV21_${width}x${height}.yuv")
        try {
            val fis = FileInputStream(file)
            fis.read(src, 0, width * height * 3 / 2)
            //420p转nv21
            YuvUtils.NV21Scale(
                src,
                width,
                height,
                dst,
                width / 5,
                height / 5,
                0
            )
            val file1 = File(getExternalFilesDir("YUV"), "cache_nv21_scale.yuv")
            val os1: OutputStream = FileOutputStream(file1)
            os1.write(dst)
            os1.flush()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        val yuvImage = YuvImage(dst, ImageFormat.NV21, width / 5, height / 5, null)
        yuvImage.compressToJpeg(
            Rect(0, 0, width / 5, height / 5),
            100,
            FileOutputStream(File(getExternalFilesDir("YUV"), "nv21_scale.jpg"))
        )

    }

    fun rotateYuv420sp() {
        val src = ByteArray(width * height * 3 / 2)
        val dst = ByteArray(width * height * 3 / 2)
        val file = File(getExternalFilesDir("YUV"), "NV21_${width}x${height}.yuv")
        try {
            val fis = FileInputStream(file)
            fis.read(src, 0, width * height * 3 / 2)
            //420p转nv21
            YuvUtils.NV21ToI420Rotate(src, width, height, dst, 90, false)
            val file1 = File(getExternalFilesDir("YUV"), "cache_nv21_rotate.yuv")
            val os1: OutputStream = FileOutputStream(file1)
            os1.write(dst)
            os1.flush()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        val nv21 = ByteArray(width * height * 3 / 2)
        YuvUtils.I420ToNV21(dst, nv21, width, height, true)
        val yuvImage = YuvImage(nv21, ImageFormat.NV21, height, width, null)
        yuvImage.compressToJpeg(
            Rect(0, 0, height, width),
            100,
            FileOutputStream(File(getExternalFilesDir("YUV"), "nv21_rotate.jpg"))
        )
    }

}